import JSZip from "jszip";
import * as THREE from "three";
import * as Comlink from "comlink";
import Config from "../config/Config";
// import { loadFile } from '../api';
import { logger } from "../utils/logger";
import {
  RenderOrderEnum,
  RESULT_WATER_COOLING_GROUP,
  TextureResultTypeEnum,
  WIREFRAME,
  waterCoolingResultKeyMap,
  ColorEnum,
  DISPERSED_LINE_GROUP,
  FACE_GROUP,
  TEXTURE_GUIDED_POINT,
  SOLID_GROUP,
  RESULT_WL_LINE_GROUP,
} from "../constants";
import {
  sleep,
  isArray,
  isString,
  hasOwnProperty,
  basename,
  noop,
  isEmpty,
  isObject,
} from "../utils/utils";
import {
  getWireframeByFace,
  getWireframeByFaces,
  makeLine,
  setPolygonOffset,
} from "../components/core/ViewUtils";
import { Line2 } from "three/examples/jsm/lines/Line2";
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial";
import { Rhino3dmLoader } from "three/examples/jsm/loaders/3DMLoader.js";
import { LineGeometry } from "three/examples/jsm/lines/LineGeometry";
import { STLLoader } from "three/examples/jsm/loaders/STLLoader";
import { LineSegments2 } from "three/examples/jsm/lines/LineSegments2";
import { LineSegmentsGeometry } from "three/examples/jsm/lines/LineSegmentsGeometry";
import rhino from "rhino";
function getMaterial({ color, opacity = 1, visible = true }) {
  const meshPhongMaterial = new THREE.MeshPhongMaterial({
    visible,
    opacity,
    color: new THREE.Color(color),
    emissive: new THREE.Color(0x333333),
    side: THREE.DoubleSide,
    transparent: opacity !== 1,
    vertexColors: false,
    fog: false,
  });
  // fix: 模型重合相交部分闪烁
  setPolygonOffset(meshPhongMaterial, 1, 4);
  return meshPhongMaterial;
}
/**
 * 检测 rhino3dm 脚本是否挂载
 * @return {Promise<Boolean>}
 */
const checkRhino3dm = () => {
  return new Promise(async (resolve) => {
    if (!window.rhino3dm) {
      await sleep(1000);
      return await checkRhino3dm();
    } else {
      return resolve(true);
    }
  });
};
/**
		 * 初始化 Rhino
		 * @return {Promise<Boolean>}
		 */
 const initRhino =()=> {
    return new Promise(async resolve => {
        if (await  checkRhino3dm()) {
            if (!window.rhino) {
                window.rhino3dm().then((rhino) => {
                    window.rhino = rhino;
                    logger.log('ReLoaded rhino3dm.');
                    return resolve(true);
                });
            } else {
                logger.log('Loaded rhino3dm.');
                return resolve(true);
            }
        }
    });
}
/**
 * rhino json数据转换为 threeJs数据
 */
export const rhinoJsonToThreeJsMesh = async (
  filePath,
  { decompress = false, isTest = false, loadingMsg = "数据加载中..." } = {}
) => {
  const objs = [];
  try {
    // this.openLoading(loadingMsg);

    if (!rhino) {
      await  initRhino();
    }

    let doc;

    // clear doc
    if (doc !== undefined) {
      doc.delete();
    }

    const getRhinoObject = (jsonData) => {
      if (jsonData && isObject(jsonData)) {
        jsonData.version = Number(jsonData.version);
        jsonData.archive3dm = Number(jsonData.archive3dm);
        jsonData.opennurbs = Number(jsonData.opennurbs);
      }
      const rhinoObject = rhino.CommonObject.decode(jsonData);
      return rhinoObject;
    };

    if (!isTest && !filePath.startsWith(Config.staticDomainURL)) {
      if (filePath.startsWith("/")) filePath = filePath.substring(1);
      filePath = Config.staticDomainURL + "/" + filePath;
    }

    let jsonDataList = [];
    if (decompress) {
      // zip解析并加载
      filePath = filePath.replace(".json", ".zip");
      const zipContent = await loadFile(filePath, "arraybuffer", false).catch(
        () => this.tipErrMsg(filePath, "结果")
      );
      jsonDataList = await this.unzip(zipContent);
    } else {
      jsonDataList = await loadFile(filePath, "json", false).catch(() =>
        this.tipErrMsg(filePath, "结果")
      );
    }

    if (!jsonDataList.length) {
      this.closeLoading();
      return objs;
    }

    const lineHandler = (rhinoObjects, objs) => {
      return new Promise((resolve) => {
        doc = new window.rhino.File3dm();

        for (const rhinoObject of rhinoObjects) {
          if (rhinoObject !== null) {
            doc.objects().add(rhinoObject, null);
          }
        }

        if (doc.objects().count < 1) {
          this.$modal.error({ content: "No objects to load!" });
          this.closeLoading();
          return;
        }

        const buffer = new Uint8Array(doc.toByteArray()).buffer;

        const loader = new Rhino3dmLoader();
        loader.setLibraryPath(`/npm/rhino3dm@7.11.1/`);

        loader.parse(buffer, (object) => {
          let lineIndex = 0;
          object.traverse((child) => {
            if (child.isMesh) {
              objs.push(child);
            }
            if (child.isLine) {
              lineIndex++;
              const jsonData = jsonDataList[lineIndex - 1];
              child.linkName = jsonData ? jsonData.faceId : undefined;
              objs.push(child);
            }
          }, false);

          // 关闭连接
          loader?.dispose?.();

          this.closeLoading();

          setTimeout(() => {
            doc.delete();
            doc = null;
          }, 300);

          return resolve(objs);
        });
      });
    };

    const rhinoObjects = [];
    for (const jsonData of jsonDataList) {
      const rhinoObject = getRhinoObject(jsonData);
      rhinoObjects.push(rhinoObject);
    }

    // console.time('loader.parse耗时');
    await lineHandler(rhinoObjects, objs);
    // console.timeEnd('loader.parse耗时');
  } catch (error) {
    logger.error("rhinoJsonToThreeJsMesh error: ", error);
  }
  return objs;
};
/**
 * 加载离散面数据
 */
export const loadRhinoFacesJson = async (type, result, isTest = false) => {
  const objs = [];
  try {
    const timeComputeStart = performance.now();

    const fileName = result[type]; // file name and include suffix
    const filePath = result.relative_path + "/" + fileName;

    if (!filePath) {
      // this.$modal.error({ content: 'loadRhinoFacesJson 文件地址丢失!' });
      return;
    }

    if (type === "meshes" || type === "faces") {
      const children = await this.rhinoJsonToThreeJsMesh(filePath, {
        isMesh: true,
        decompress: false,
        isTest,
      });
      let meshIndex = 0;
      for (const child of children) {
        meshIndex++;
        child.material = getMaterial({ color: ColorEnum.default });
        // child.material = getMatCapMaterial();
        if (type === "meshes") {
          child.isSolid = true;
          child.groupName = SOLID_GROUP;
          child.nickname = "solid_" + meshIndex;
          child.renderOrder = RenderOrderEnum.solid;
        }
        if (type === "faces") {
          child.isFace = true;
          child.groupName = FACE_GROUP;
          child.nickname = "face_" + meshIndex;
          child.renderOrder = RenderOrderEnum.face;
        }
        child.canDelete = true;
        child.castShadow = true;
        child.solidGroup = "solid_1"; // 目前仅支持单体

        // 根据离散面计算边框
        // const wireframe = getWireframeByFace(child, this.getCanvas(), 1);
        // wireframe.canDelete = true;
        // wireframe.isWireframe = true; // 是否线框
        // wireframe.groupName = WIREFRAME;
        // wireframe.nickname = 'w_' + meshIndex;
        // wireframe.renderOrder = RenderOrderEnum.line;
        // 插入边框
        // objs.push(wireframe);

        // 插入face
        objs.push(child);
      }

      // 获取线框（多个面）
      const wireframe = getWireframeByFaces(children, this.getCanvas(), 1);
      wireframe.canDelete = true;
      wireframe.isWireframe = true; // 是否线框
      wireframe.groupName = WIREFRAME;
      wireframe.nickname = "w_" + meshIndex;
      wireframe.renderOrder = RenderOrderEnum.line;
      objs.push(wireframe);
    }

    const t1 = performance.now();
    const computeSolveTime = t1 - timeComputeStart;
    logger.log(`loadRhinoFacesJson 耗时: ${Math.round(computeSolveTime)} ms`);
  } catch (error) {
    logger.error("loadRhinoFacesJson error: ", error);
  }
};
